﻿using Furion.DatabaseAccessor;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using FurionApiDemo.Core.ApiResult;
using FurionApiDemo.Core.Const;
using FurionApiDemo.Core.Entity;
using FurionApiDemo.Core.Implement.Auth.Dtos;
using FurionApiDemo.Core.Manager;
using FurionApiDemo.Core.Manager.User;
using FurionApiDemo.Core.SignalRHub;
using FurionApiDemo.Util.Helper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FurionApiDemo.Core.Implementt.Auth
{
    public class AuthService : IAuthService, ITransient
    {
        private readonly IRepository<SysUser> _sysUserRep;     // 用户表仓储  
        private readonly IRepository<SysUserInfo> _sysUserInfoRep;     // 用户表仓储  
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IUserManager _userManager; // 用户管理
        private readonly IHubContext<SignalRMessageHub> _messageHub;

        private readonly ILogger<UserService> _logger;

        public AuthService(IRepository<SysUser> sysUserRep,
            IHttpContextAccessor httpContextAccessor,
            IUserManager userManager,
            ILogger<UserService> logger, IRepository<SysUserInfo> sysUserInfoRep,
            IHubContext<SignalRMessageHub> messageHub)
        {
            _sysUserRep = sysUserRep;
            _httpContextAccessor = httpContextAccessor;
            _userManager = userManager;
            _logger = logger;
            _sysUserInfoRep = sysUserInfoRep;
            _messageHub = messageHub;
        }

        public async Task<LoginOutput> LoginAsync(LoginInput input)
        {
            var result = new LoginOutput();

            // 获取加密后的密码
            var encryptPasswod = MD5Encryption.Encrypt(input.Password);

            // 判断用户名和密码是否正确
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.UserName.Equals(input.UserName) && u.Password.Equals(encryptPasswod));
            _ = user ?? throw Oops.Oh(ErrorCode.D1000);

            user.SysUserInfo = await _sysUserInfoRep.FirstOrDefaultAsync(u => u.UserId == user.Id);

            // 验证账号是否被冻结
            if (user.Status == (int)CommonStatus.DISABLE)
                throw Oops.Oh(ErrorCode.D1017);

            // 生成Token令牌
            //var accessToken = await _jwtBearerManager.CreateTokenAdmin(user);
            var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
                {
                    { ClaimConst.CLAINM_USERID, user.Id },
                    { ClaimConst.CLAINM_USER_NAME, user.UserName },
                    { ClaimConst.CLAINM_NAME, user.SysUserInfo.NickName },
                    { ClaimConst.CLAINM_SUPERADMIN, user.AdminType },
                }, 120);

            // 设置Swagger自动登录
            _httpContextAccessor.HttpContext.SigninToSwagger(accessToken);

            // 生成刷新Token令牌
            var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30);

            // 设置刷新Token令牌
            _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;

            result.Token = accessToken;
            result.RefreshToken = refreshToken;

            return result;
        }

        /// <summary>
        /// 登出
        /// </summary>
        /// <returns></returns>
        public async Task LogoutAsync()
        {
            // 设置Swagger自动登录
            _httpContextAccessor.HttpContext.SignoutToSwagger();
        }

        public Task<CaptchaOutput> GetCaptcha()
        {
            var result = new CaptchaOutput();
            Tuple<string, int> captchaCode = CaptchaHelper.GetCaptchaCode();
            byte[] bytes = CaptchaHelper.CreateCaptchaImage(captchaCode.Item1);
            result.CaptchaBase64 = Convert.ToBase64String(bytes);
            result.CaptchaResult = captchaCode.Item2;
            return Task.FromResult(result);
        }

        public async Task SetLoginInfo()
        {
            var user = _userManager.User;
            user.LastLoginIp = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4();
            user.LastLoginTime = DateTime.Now;
            await _sysUserRep.UpdateIncludeAsync(user, new[] { "LastLoginIp", "LastLoginTime" });
        }
    }
}
